package studio.baka.satoripixeldungeon.actors.mobs.npcs;

import studio.baka.satoripixeldungeon.Assets;
import studio.baka.satoripixeldungeon.Dungeon;
import studio.baka.satoripixeldungeon.actors.Char;
import studio.baka.satoripixeldungeon.actors.buffs.Buff;
import studio.baka.satoripixeldungeon.actors.buffs.Paralysis;
import studio.baka.satoripixeldungeon.actors.buffs.Roots;
import studio.baka.satoripixeldungeon.actors.mobs.FetidRat;
import studio.baka.satoripixeldungeon.actors.mobs.GnollTrickster;
import studio.baka.satoripixeldungeon.actors.mobs.GreatCrab;
import studio.baka.satoripixeldungeon.actors.mobs.Mob;
import studio.baka.satoripixeldungeon.effects.CellEmitter;
import studio.baka.satoripixeldungeon.effects.Speck;
import studio.baka.satoripixeldungeon.items.Generator;
import studio.baka.satoripixeldungeon.items.armor.*;
import studio.baka.satoripixeldungeon.items.weapon.Weapon;
import studio.baka.satoripixeldungeon.items.weapon.melee.MeleeWeapon;
import studio.baka.satoripixeldungeon.journal.Notes;
import studio.baka.satoripixeldungeon.levels.SewerLevel;
import studio.baka.satoripixeldungeon.messages.Messages;
import studio.baka.satoripixeldungeon.scenes.GameScene;
import studio.baka.satoripixeldungeon.sprites.GhostSprite;
import studio.baka.satoripixeldungeon.utils.GLog;
import studio.baka.satoripixeldungeon.windows.WndQuest;
import studio.baka.satoripixeldungeon.windows.WndSadGhost;
import com.watabou.noosa.Game;
import com.watabou.noosa.audio.Sample;
import com.watabou.utils.Bundle;
import com.watabou.utils.Random;
import com.watabou.utils.Reflection;

public class Ghost extends NPC {

    {
        spriteClass = GhostSprite.class;

        flying = true;

        state = WANDERING;
    }

    public Ghost() {
        super();

        Sample.INSTANCE.load(Assets.SND_GHOST);
    }

    @Override
    protected boolean act() {
        if (Quest.processed())
            target = Dungeon.hero.pos;
        return super.act();
    }

    @Override
    public int defenseSkill(Char enemy) {
        return 100_000_000;
    }

    @Override
    public float speed() {
        return Quest.processed() ? 2f : 0.5f;
    }

    @Override
    protected Char chooseEnemy() {
        return null;
    }

    @Override
    public void damage(int dmg, Object src) {
    }

    @Override
    public void add(Buff buff) {
    }

    @Override
    public boolean reset() {
        return true;
    }

    @Override
    public boolean interact() {
        sprite.turnTo(pos, Dungeon.hero.pos);

        Sample.INSTANCE.play(Assets.SND_GHOST);

        if (Quest.given) {
            if (Quest.weapon != null) {
                if (Quest.processed) {
                    Game.runOnRenderThread(() -> GameScene.show(new WndSadGhost(Ghost.this, Quest.type)));
                } else {
                    Game.runOnRenderThread(() -> {
                        switch (Quest.type) {
                            case 1:
                            default:
                                GameScene.show(new WndQuest(Ghost.this, Messages.get(Ghost.this, "rat_2")));
                                break;
                            case 2:
                                GameScene.show(new WndQuest(Ghost.this, Messages.get(Ghost.this, "gnoll_2")));
                                break;
                            case 3:
                                GameScene.show(new WndQuest(Ghost.this, Messages.get(Ghost.this, "crab_2")));
                                break;
                        }
                    });

                    int newPos = -1;
                    for (int i = 0; i < 10; i++) {
                        newPos = Dungeon.level.randomRespawnCell();
                        if (newPos != -1) {
                            break;
                        }
                    }
                    if (newPos != -1) {

                        CellEmitter.get(pos).start(Speck.factory(Speck.LIGHT), 0.2f, 3);
                        pos = newPos;
                        sprite.place(pos);
                        sprite.visible = Dungeon.level.heroFOV[pos];
                    }
                }
            }
        } else {
            Mob questBoss;
            String txt_quest;

            switch (Quest.type) {
                case 1:
                default:
                    questBoss = new FetidRat();
                    txt_quest = Messages.get(this, "rat_1", Dungeon.hero.givenName());
                    break;
                case 2:
                    questBoss = new GnollTrickster();
                    txt_quest = Messages.get(this, "gnoll_1", Dungeon.hero.givenName());
                    break;
                case 3:
                    questBoss = new GreatCrab();
                    txt_quest = Messages.get(this, "crab_1", Dungeon.hero.givenName());
                    break;
            }

            questBoss.pos = Dungeon.level.randomRespawnCell();

            if (questBoss.pos != -1) {
                GameScene.add(questBoss);
                Quest.given = true;
                Notes.add(Notes.Landmark.GHOST);
                Game.runOnRenderThread(() -> GameScene.show(new WndQuest(Ghost.this, txt_quest)));
            }

        }

        return false;
    }

    {
        immunities.add(Paralysis.class);
        immunities.add(Roots.class);
    }

    public static class Quest {

        private static boolean spawned;

        private static int type;

        private static boolean given;
        private static boolean processed;

        private static int depth;

        public static Weapon weapon;
        public static Armor armor;

        public static void reset() {
            spawned = false;

            weapon = null;
            armor = null;
        }

        private static final String NODE = "sadGhost";

        private static final String SPAWNED = "spawned";
        private static final String TYPE = "type";
        private static final String GIVEN = "given";
        private static final String PROCESSED = "processed";
        private static final String DEPTH = "depth";
        private static final String WEAPON = "weapon";
        private static final String ARMOR = "armor";

        public static void storeInBundle(Bundle bundle) {

            Bundle node = new Bundle();

            node.put(SPAWNED, spawned);

            if (spawned) {

                node.put(TYPE, type);

                node.put(GIVEN, given);
                node.put(DEPTH, depth);
                node.put(PROCESSED, processed);

                node.put(WEAPON, weapon);
                node.put(ARMOR, armor);
            }

            bundle.put(NODE, node);
        }

        public static void restoreFromBundle(Bundle bundle) {

            Bundle node = bundle.getBundle(NODE);

            if (node.notNull() && (spawned = node.getBoolean(SPAWNED))) {

                type = node.getInt(TYPE);
                given = node.getBoolean(GIVEN);
                processed = node.getBoolean(PROCESSED);

                depth = node.getInt(DEPTH);

                weapon = (Weapon) node.get(WEAPON);
                armor = (Armor) node.get(ARMOR);
            } else {
                reset();
            }
        }

        public static void spawn(SewerLevel level) {
            if (!spawned && Dungeon.depth > 1 && Random.Int(5 - Dungeon.depth) == 0) {

                Ghost ghost = new Ghost();
                do {
                    ghost.pos = level.randomRespawnCell();
                } while (ghost.pos == -1);
                level.mobs.add(ghost);

                spawned = true;
                //dungeon depth determines type of quest.
                //depth2=fetid rat, 3=gnoll trickster, 4=great crab
                type = Dungeon.depth - 1;

                given = false;
                processed = false;
                depth = Dungeon.depth;

                //50%:tier2, 30%:tier3, 15%:tier4, 5%:tier5
                float itemTierRoll = Random.Float();
                int wepTier;

                if (itemTierRoll < 0.5f) {
                    wepTier = 2;
                    armor = new LeatherArmor();
                } else if (itemTierRoll < 0.8f) {
                    wepTier = 3;
                    armor = new MailArmor();
                } else if (itemTierRoll < 0.95f) {
                    wepTier = 4;
                    armor = new ScaleArmor();
                } else {
                    wepTier = 5;
                    armor = new PlateArmor();
                }

                Generator.Category c = Generator.wepTiers[wepTier - 1];
                weapon = (MeleeWeapon) Reflection.newInstance(c.classes[Random.chances(c.probs)]);

                //50%:+0, 30%:+1, 15%:+2, 5%:+3
                float itemLevelRoll = Random.Float();
                int itemLevel;
                if (itemLevelRoll < 0.5f) {
                    itemLevel = 0;
                } else if (itemLevelRoll < 0.8f) {
                    itemLevel = 1;
                } else if (itemLevelRoll < 0.95f) {
                    itemLevel = 2;
                } else {
                    itemLevel = 3;
                }
                weapon.upgrade(itemLevel);
                armor.upgrade(itemLevel);

                //10% to be enchanted
                if (Random.Int(10) == 0) {
                    weapon.enchant();
                    armor.inscribe();
                }

            }
        }

        public static void process() {
            if (spawned && given && !processed && (depth == Dungeon.depth)) {
                GLog.n(Messages.get(Ghost.class, "find_me"));
                Sample.INSTANCE.play(Assets.SND_GHOST);
                processed = true;
            }
        }

        public static void complete() {
            weapon = null;
            armor = null;

            Notes.remove(Notes.Landmark.GHOST);
        }

        public static boolean processed() {
            return spawned && processed;
        }

        public static boolean completed() {
            return processed() && weapon == null && armor == null;
        }
    }
}
